from typing import List, Optional, Union

from sqlalchemy import select, update, delete, func
from sqlalchemy.ext.asyncio import AsyncSession

from module_kylin.entity.do.future_account_do import KylinFutureAccount
from module_kylin.entity.vo.future_account_vo import FutureAccountPageQueryModel
from utils.page_util import PageUtil


class FutureAccountDao:
    """
    期货账户数据库操作层
    """

    @classmethod
    async def get_account_by_id(cls, db: AsyncSession, account_id: int):
        """
        根据ID获取期货账户信息

        :param db: orm对象
        :param account_id: 账户id
        :return: 期货账户信息对象
        """
        account_info = (
            await db.execute(select(KylinFutureAccount).where(KylinFutureAccount.id == account_id))
        ).scalars().first()

        return account_info

    @classmethod
    async def get_account_by_name(cls, db: AsyncSession, account_name: str):
        """
        根据账户名称获取期货账户信息

        :param db: orm对象
        :param account_name: 账户名称
        :return: 期货账户信息对象
        """
        account_info = (
            await db.execute(select(KylinFutureAccount).where(KylinFutureAccount.account_name == account_name))
        ).scalars().first()

        return account_info

    @classmethod
    async def get_account_list(cls, db: AsyncSession, query_object: FutureAccountPageQueryModel, is_page: bool = False):
        """
        获取期货账户列表

        :param db: orm对象
        :param query_object: 查询参数对象
        :param is_page: 是否开启分页
        :return: 期货账户列表
        """
        # 构建查询
        query = select(KylinFutureAccount)

        # 添加查询条件
        if query_object.account_code is not None:
            query = query.where(KylinFutureAccount.account_code.like(f'%{query_object.account_code}%'))
        if query_object.account_name is not None:
            query = query.where(KylinFutureAccount.account_name.like(f'%{query_object.account_name}%'))
        if query_object.futures_company is not None:
            query = query.where(KylinFutureAccount.futures_company.like(f'%{query_object.futures_company}%'))
        if query_object.settlement_account is not None:
            query = query.where(KylinFutureAccount.settlement_account.like(f'%{query_object.settlement_account}%'))

        # 执行查询
        if is_page:
            # 分页查询
            account_list_result = await PageUtil.paginate(
                db=db,
                query=query,
                page_num=query_object.page_num,
                page_size=query_object.page_size,
                is_page=True
            )
        else:
            # 普通查询
            account_list = (await db.execute(query)).scalars().all()
            account_list_result = account_list

        return account_list_result

    @classmethod
    async def add_account(cls, db: AsyncSession, account: FutureAccountPageQueryModel):
        """
        添加期货账户

        :param db: orm对象
        :param account: 期货账户对象
        :return: 操作结果
        """
        db_account = KylinFutureAccount(
            account_code=account.account_code,
            account_name=account.account_name,
            futures_company=account.futures_company,
            settlement_account=account.settlement_account,
            settlement_password=account.settlement_password,
            trade_username=account.trade_username,
            trade_password=account.trade_password,
            broker_code=account.broker_code,
            trade_server=account.trade_server,
            market_server=account.market_server,
            product_name=account.product_name,
            auth_code=account.auth_code,
            product_info=account.product_info
        )
        db.add(db_account)
        await db.flush()
        return db_account

    @classmethod
    async def update_account(cls, db: AsyncSession, account_id: int, account: FutureAccountPageQueryModel):
        """
        更新期货账户

        :param db: orm对象
        :param account_id: 账户id
        :param account: 期货账户对象
        :return: 操作结果
        """
        update_data = {}
        if account.account_code is not None:
            update_data[KylinFutureAccount.account_code] = account.account_code
        if account.account_name is not None:
            update_data[KylinFutureAccount.account_name] = account.account_name
        if account.futures_company is not None:
            update_data[KylinFutureAccount.futures_company] = account.futures_company
        if account.settlement_account is not None:
            update_data[KylinFutureAccount.settlement_account] = account.settlement_account
        if account.settlement_password is not None:
            update_data[KylinFutureAccount.settlement_password] = account.settlement_password
        if account.trade_username is not None:
            update_data[KylinFutureAccount.trade_username] = account.trade_username
        if account.trade_password is not None:
            update_data[KylinFutureAccount.trade_password] = account.trade_password
        if account.broker_code is not None:
            update_data[KylinFutureAccount.broker_code] = account.broker_code
        if account.trade_server is not None:
            update_data[KylinFutureAccount.trade_server] = account.trade_server
        if account.market_server is not None:
            update_data[KylinFutureAccount.market_server] = account.market_server
        if account.product_name is not None:
            update_data[KylinFutureAccount.product_name] = account.product_name
        if account.auth_code is not None:
            update_data[KylinFutureAccount.auth_code] = account.auth_code
        if account.product_info is not None:
            update_data[KylinFutureAccount.product_info] = account.product_info
        
        await db.execute(
            update(KylinFutureAccount)
            .where(KylinFutureAccount.id == account_id)
            .values(update_data)
        )

    @classmethod
    async def delete_account(cls, db: AsyncSession, account_ids: List[int]):
        """
        删除期货账户

        :param db: orm对象
        :param account_ids: 账户id列表
        :return: 操作结果
        """
        await db.execute(
            delete(KylinFutureAccount)
            .where(KylinFutureAccount.id.in_(account_ids))
        )

    @classmethod
    async def get_total_accounts(cls, db: AsyncSession):
        """
        获取期货账户总数

        :param db: orm对象
        :return: 账户总数
        """
        total = await db.scalar(select(func.count()).select_from(KylinFutureAccount))
        return total